﻿using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using Foxit.PDF;
using Foxit.PDF.PageElements;
using Foxit.PDF.IO;
using System;
using Sustainalytics.Reporting.Framework;

namespace Sustainalytics.ReportGenerator.BL
{
    public class QualitativePerformanceChart : PageElement
    {
        public float Left { get; set; }
        public float Top { get; set; }
        public float Width { get; set; }
        public float Height { get; set; }

        public List<ControversyCategory> QualitativePerformance { get; set; }
        public List<PageElementPosition> PageElementPositions { get; set; }


        public QualitativePerformanceChart(float left, float top, float width, float height)
        {
            Left = left;
            Top = top;
            Width = width;
            Height = height;
        }

        private Group Chart()
        {
            var pageElements = new Group();
            PageElementPositions = new List<PageElementPosition>();

            var maxHeight = Top + Height;
            var maxAnswerCategory = 0;

            if (QualitativePerformance.Any())
            {
                maxAnswerCategory = QualitativePerformance.Max(qp => qp.AnswerCategory);
            }

            const string highestControversyLevelText = "Highest Controversy Level";

            const float maxCtgBulletradius = 17.5f;
            const float borderWidth = 0.5f;
            const float maxCtgTitleFontSize = 24f;
            const float maxCtgSeverityFontSize = 10f;
            const float maxCtgFontSize = 8f;
            
            pageElements.Add(
                new Circle(Left + maxCtgBulletradius, Top + maxCtgBulletradius, maxCtgBulletradius, maxCtgBulletradius,
                    Colors.CtgColor[maxAnswerCategory], Colors.CtgColor[maxAnswerCategory], borderWidth, LineStyle.Solid));
            
            pageElements.Add(
                new Label(maxAnswerCategory.ToString(CultureInfo.InvariantCulture), Left, Top + 6f, maxCtgBulletradius * 2,
                    maxCtgTitleFontSize + 2f, Fonts.CalibriBold, maxCtgTitleFontSize, TextAlign.Center, RgbColor.White));
            
            pageElements.Add(
                new Label(highestControversyLevelText, Left + 40f, Top + 5f, 120f,
                    maxCtgSeverityFontSize + 2f, Fonts.CalibriBold, maxCtgSeverityFontSize, TextAlign.Left, RgbColor.Black));
            
            pageElements.Add(new Line(Left + 40f, Top + maxCtgBulletradius, Left + 155f, 
                Top + maxCtgBulletradius, 0.3f, RgbColor.Black));


            var top = Top + maxCtgBulletradius;
            var leftMaxCtg = Left + 40f;
            var topMaxCtg = top + 5f;

            FormattedTextArea formattedTextArea;
            float textHeight;
            var ciNameWidth = 100f;
            var eiNameWidth = 100f;

            if (maxAnswerCategory > 0 && QualitativePerformance.Any())
            {
                var eventIndicators = QualitativePerformance
                    .Where(qp => qp.AnswerCategory == maxAnswerCategory)
                    .OrderBy(qp => qp.ControversyIndicatorSortKey)
                    .ThenBy(qp => qp.BaseEventIndicatorName)
                    .ToList();

                if (eventIndicators.Any())
                {
                    var controversyIndicatorId = Guid.Empty;

                    foreach (var eventIndicator in eventIndicators)
                    {
                        if (topMaxCtg > maxHeight)
                        {
                            pageElements.Add(
                                new Label("...", leftMaxCtg, topMaxCtg, 50f,
                                    maxCtgFontSize + 2, Fonts.CalibriBold, maxCtgFontSize, TextAlign.Left, RgbColor.Black));
                        }
                        else
                        {
                            if (controversyIndicatorId != eventIndicator.ControversyIndicatorId)
                            {
                                formattedTextArea = new FormattedTextArea(
                                    string.Format("<b>{0}</b>", eventIndicator.ControversyIndicatorName),
                                    leftMaxCtg, topMaxCtg, ciNameWidth, 50f, Fonts.CalibriFontFamily, maxCtgFontSize, true);

                                textHeight = (float) Math.Round((decimal) formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

                                formattedTextArea = new FormattedTextArea(
                                    string.Format("<b>{0}</b>", eventIndicator.ControversyIndicatorName),
                                    leftMaxCtg, topMaxCtg, ciNameWidth, textHeight, Fonts.CalibriFontFamily,
                                    maxCtgFontSize, true);

                                pageElements.Add(new Rectangle(leftMaxCtg, topMaxCtg, ciNameWidth, textHeight, RgbColor.White, RgbColor.White));
                                pageElements.Add(formattedTextArea);

                                PageElementPositions.Add(new PageElementPosition
                                {
                                    Id = eventIndicator.ControversyIndicatorId,
                                    Name = eventIndicator.ControversyIndicatorName,
                                    HorizontalPosition = leftMaxCtg,
                                    VerticalPosition = topMaxCtg,
                                    Height = textHeight,
                                    Width = ciNameWidth
                                });

                                topMaxCtg += textHeight;
                            }

                            formattedTextArea = new FormattedTextArea(eventIndicator.BaseEventIndicatorName,
                                leftMaxCtg, topMaxCtg, eiNameWidth, 50f, Fonts.CalibriLightFontFamily, maxCtgFontSize, true);
                            
                            textHeight = (float) Math.Round((decimal) formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);
                            
                            formattedTextArea = new FormattedTextArea(eventIndicator.BaseEventIndicatorName,
                                leftMaxCtg, topMaxCtg, eiNameWidth, textHeight, Fonts.CalibriLightFontFamily, maxCtgFontSize, true);

                            pageElements.Add(new Rectangle(leftMaxCtg, topMaxCtg, eiNameWidth, textHeight, RgbColor.White, RgbColor.White));
                            pageElements.Add(formattedTextArea);

                            PageElementPositions.Add(new PageElementPosition
                            {
                                Id = eventIndicator.BaseEventIndicatorId,
                                Name = eventIndicator.BaseEventIndicatorName,
                                HorizontalPosition = leftMaxCtg,
                                VerticalPosition = topMaxCtg,
                                Height = textHeight,
                                Width = eiNameWidth
                            });

                            topMaxCtg += textHeight + 2f;
                        }

                        controversyIndicatorId = eventIndicator.ControversyIndicatorId;
                    }
                }
            }

            if (maxAnswerCategory == 0)
            {
                pageElements.Add(
                    new Label("None", Left + 40f, top + 5f, 120f,
                        maxCtgFontSize + 2f, Fonts.CalibriLight, maxCtgFontSize, TextAlign.Left, RgbColor.Black));
            }


            int ctg;
            var leftCtg = Left + 175f;
            const float ctgBulletradius = 9f;
            const float ctgTitleFontSize = 13f;
            const float ctgSeverityFontSize = 8f;
            const float ctgFontSize = 6f;
            const float ctgOffset = 73f;

            for (ctg = 1; ctg <= 5; ctg++)
            {
                pageElements.Add(
                    new Circle(leftCtg + ctgBulletradius, top, ctgBulletradius, ctgBulletradius,
                        Colors.CtgColor[ctg], Colors.CtgColor[ctg], borderWidth, LineStyle.Solid));
                pageElements.Add(
                    new Label(ctg.ToString(CultureInfo.InvariantCulture), leftCtg + 1f, top - ctgBulletradius + 3f, 15f,
                        ctgTitleFontSize + 2f, Fonts.CalibriBold, ctgTitleFontSize, TextAlign.Center, RgbColor.White));
                pageElements.Add(
                    new Label(GetEventSeverity(ctg), leftCtg + 23f, top - ctgBulletradius, 60f,
                        ctgSeverityFontSize + 2, Fonts.CalibriBold, ctgSeverityFontSize, TextAlign.Left, RgbColor.Black));
                pageElements.Add(
                    new Line(leftCtg + 23f, top, leftCtg + 60f, top, 0.3f, RgbColor.Black));

                leftCtg = leftCtg + ctgOffset;
            }

            float leftText;
            var topText = new float[5];

            for (var i = 0; i < 5; i++)
            {
                topText[i] = top + 5f;
            }

            var categoryHasControversies = new[] { false, false, false, false, false };

            ciNameWidth = 50f;
            eiNameWidth = 60f;

            if (QualitativePerformance.Any())
            {
                for (var awnswerCategory = 1; awnswerCategory <= 5; awnswerCategory++)
                {
                    var eventIndicators = QualitativePerformance.Where(qp => qp.AnswerCategory == awnswerCategory)
                        .OrderBy(qp => qp.ControversyIndicatorSortKey)
                        .ThenBy(qp => qp.BaseEventIndicatorName)
                        .ToList();

                    if (!eventIndicators.Any()) continue;

                    var controversyIndicatorId = Guid.Empty;

                    foreach (var eventIndicator in eventIndicators)
                    {
                        ctg = eventIndicator.AnswerCategory - 1;

                        categoryHasControversies[ctg] = true;

                        leftText = Left + 175f + 23f + (ctg * ctgOffset);

                        if (topText[ctg] > maxHeight)
                        {
                            pageElements.Add(
                                new Label("...", leftText, topText[ctg], 50f, 
                                    ctgFontSize + 2, Fonts.CalibriBold, ctgFontSize, TextAlign.Left, RgbColor.Black));
                        }
                        else
                        {
                            if (controversyIndicatorId != eventIndicator.ControversyIndicatorId)
                            {
                                formattedTextArea = new FormattedTextArea(
                                    string.Format("<b>{0}</b>", eventIndicator.ControversyIndicatorName),
                                    leftText, topText[ctg], ciNameWidth, 50f, Fonts.CalibriFontFamily, ctgFontSize, true);

                                textHeight = (float) Math.Round((decimal) formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

                                formattedTextArea = new FormattedTextArea(
                                    string.Format("<b>{0}</b>", eventIndicator.ControversyIndicatorName),
                                    leftText, topText[ctg], ciNameWidth, textHeight, Fonts.CalibriFontFamily,
                                    ctgFontSize, true);

                                pageElements.Add(new Rectangle(leftText, topText[ctg], ciNameWidth, textHeight, RgbColor.White, RgbColor.White));
                                pageElements.Add(formattedTextArea);

                                PageElementPositions.Add(new PageElementPosition
                                {
                                    Id = eventIndicator.ControversyIndicatorId,
                                    Name = eventIndicator.ControversyIndicatorName,
                                    HorizontalPosition = leftText,
                                    VerticalPosition = topText[ctg],
                                    Height = textHeight,
                                    Width = ciNameWidth
                                });

                                topText[ctg] += textHeight;
                            }

                            formattedTextArea = new FormattedTextArea(eventIndicator.BaseEventIndicatorName,
                                leftText, topText[ctg], eiNameWidth, 50f, Fonts.CalibriLightFontFamily, ctgFontSize, true);
                            
                            textHeight = (float)Math.Round((decimal)formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);
                            
                            formattedTextArea = new FormattedTextArea(eventIndicator.BaseEventIndicatorName,
                                leftText, topText[ctg], eiNameWidth, textHeight, Fonts.CalibriLightFontFamily, ctgFontSize, true);

                            pageElements.Add(new Rectangle(leftText, topText[ctg], eiNameWidth, textHeight, RgbColor.White, RgbColor.White));
                            pageElements.Add(formattedTextArea);

                            PageElementPositions.Add(new PageElementPosition
                            {
                                Id = eventIndicator.BaseEventIndicatorId,
                                Name = eventIndicator.BaseEventIndicatorName,
                                HorizontalPosition = leftText,
                                VerticalPosition = topText[ctg],
                                Height = textHeight,
                                Width = eiNameWidth
                            });

                            topText[ctg] += textHeight + 2f;
                        }

                        controversyIndicatorId = eventIndicator.ControversyIndicatorId;
                    }
                }
            }

            for (ctg = 0; ctg < 5; ctg++)
            {
                leftText = Left + 175f + 23f + (ctg * ctgOffset);

                if (!categoryHasControversies[ctg])
                    pageElements.Add(
                        new Label("None", leftText, top + 5f, 50f,
                            ctgFontSize + 2, Fonts.CalibriLight, ctgFontSize, TextAlign.Left, RgbColor.Black));
            }

            return pageElements;
        }

        public void PreDraw()
        {
            Chart();
        }

        private static string GetEventSeverity(int category)
        {
            switch (category)
            {
                case 1:
                    return "Low";
                case 2:
                    return "Moderate";
                case 3:
                    return "Significant";
                case 4:
                    return "High";
                case 5:
                    return "Severe";
                default:
                    return string.Empty;
            }
        }

        public override void Draw(PageWriter writer)
        {
            var chart = Chart();

            writer.Write_q_(true);
            chart.Draw(writer);
            writer.Write_Q(true);
        }
    }

}
